/**
 * @note 类型判定函数
 * @param {Object} obj [ 实例对象 ]
 * @return {String}
 * */
function is(obj){
    return Object.prototype.toString.call(obj).slice(8,-1);
}

// 验证器单例对象
let validator = {};

// 策略对象
validator.types = {};

// 打印对应字段的验证结果
validator.print = false;

/**
 * @note 非空验证
 * @param {String | Array | Boolean} data [ 验证的数据 ]
 * @return {Boolean}
 * */
validator.isNotEmpty = function(data){
    let validate = true,
        regTrim = /^\s+|\s+$/g;
    switch(is(data)){
        // 不需要考虑 Number 类型
        case 'String':
            data = data.replace(regTrim,'');
            data == '' && (validate = false);
            break;
        case 'Array':
            data.length == 0 && (validate = false);
            break;
        case 'Boolean':
            !data && (validate = false);
            break;
    }
    return validate;
}

/**
 * @note 非空验证器
 * @param {String | Array} data [ 当前字段数据 ]
 * @pram {Object} rule [ 验证对象 ]
 * @return {Boolean}
 * */
validator.types.required = function(data,rule){
    let validate = true;
    
    // 非必填 直接 return true;
    if(!rule.value){
        return true;
    }
    
    validate = validator.isNotEmpty(data);
    // 无论是否错误都记录错误信息 - 由于存在正则数组类型的错误列表，所以将具体的错误信息记录到函数的静态属性上
    arguments.callee.message = rule.message;
    return validate;
}

/**
 * @note 正则验证器
 * @param {String | Array} data [ 当前字段数据 ]
 * @param {Object} rule [ 验证对象 ]
 * @return {Boolean}
 * */
validator.types.regexp = function(data,rule){
    let validate = true;
    
    switch(is(rule.value)){
        case 'Array':
            // 循环验证
            for(let i = 0,len = rule.value.length;i < len;i++){
                let reg = rule.value[i];
                validate = reg.test(data);
                // 验证未通过
                if(!validate){
                    arguments.callee.message = rule.message[i];
                    break;
                }
            }
            break;
        case 'RegExp':
            validate = rule.value.test(data);
            if(!validate){
                arguments.callee.message = rule.message;
            }
            break;
    }
    return validate;
}

/**
 * @note 自定义验证函数 - 需要将错误信息写入自定义验证器的函数静态属性 [validate.message]，验证器读取次属性存储错误信息
 * @param {String | Array} data [ 当前字段数据 ]
 * @param {Object} dataObj [ 需要验证的整体数据 ]
 * @param {Function} rule [ 自定义的验证函数 ]
 * @return {Boolean}
 * */
validator.types.validate = function(data,dataObj,rule){
    return rule(data,dataObj);
}

// 整体验证 [ 默认 ]
validator.validate = function(dataObj,ruleObj,checkAll = false){
    let types = validator.types,
        validate = true,
        // 待验证的字段集合
        fields = Object.keys(rules);
    // 错误信息记录
    validator.fields = [];
    validator.messages = [];
    for(let i = 0,len = fields.length;i < len;i++){
        let checked = true,
            field = fields[i],
            data = dataObj[field],
            rule = ruleObj[field];
        checked = validator.validateField(data,rule,dataObj,field);
        !checked && (validate = false);
        if(checkAll){
            if(!checked){  // 记录错误信息
                validator.fields.push(validator.field);
                validator.messages.push(validator.message);
            }
            continue;
        }
        if(!checked){
            return validate;
        }
    }
    // 第一个出口
    return validate;
}

// 字段验证
/**
 * @note 字段验证
 * @param {String || Array || Boolean} data [ 需要验证的数据 ]
 * @param {Object} rule [ 验证规则 ]
 * @param {Object} dataObj [ 整体数据 ]
 * @param {String} field [ 需要验证的数据字段 ]
 * @return {Boolean}
 * */
validator.validateField = function(data,rule,dataObj = {},field = ''){
    let validate = true,
        ruleFields = Object.keys(rule),
        types = validator.types,    // 策略对象
        isRequired = rule.hasOwnProperty('required') && rule['required'].value === true,    // 必填项验证
        isIgnoreRequired = rule.hasOwnProperty('ignoreRequired') && rule['ignoreRequired'].value === true;  // 忽略 必填 和非必填 约束
    for(let i = 0,len = ruleFields.length;i < len;i++){
        let ruleField = ruleFields[i],  // 策略属性
            checked = true;
        if(!types.hasOwnProperty(ruleField)){   // 不存在对应的策略对象
            continue;
        }
        if(ruleField == 'validate'){ // 区别对待 validate 策略 [ 需要多传入 dataObj 参数提供给自定义验证 ]
            checked = types[ruleField](data,dataObj,rule['validate']);
        }else{
            checked = types[ruleField](data,rule[ruleField]);
        }
        if(!isIgnoreRequired){   // 矫正验证结果
            (!isRequired && !validator.isNotEmpty(data)) && (checked = true);
        }
        !checked && (validate = false);
        if(!checked){
            validator.field = field;    // 记录错误字段
            if(ruleField == 'validate'){    // 记录错误结果
                validator.message = rule['validate'].message;
            }else{
                validator.message = types[ruleField].message;
            }
            return validate;
        }
    }
    return validate;
}

export default validator;

/*let form = {
        username:'huoshen1128',
        password:'123456',
        hoppy:'1111111111111'
    },
    rules = {
        username:{
            required:{
                value:true,
                message:'用户名不能为空'
            },
            regexp:{
                // 单个时只需要输入一个正则即可
                value:[/^[a-z0-9]*$/i,/^[\s\S]{6,20}$/],
                message:['用户名只能输入字母','用户名的密码长度为6~8位']
            }
        },
        //存在 valiate 时，无视 required 选项, 如果验证失败，需要将失败信息写入到 validate 的 message 属性
        password:{
            validate(data,dataObj){
                // 不予通过 demo
                arguments.callee.message = '密码不行啊';
                return false;
            },
            //存在 validate 时，会检测是否需要忽略 required 因素
            ignoreRequired:false
        },
        hoppy:{
            regexp:{
                value:/^\w{0,10}$/,
                message:'最多只能输入10个字符'
            }
        }
    };*/
/**
 * @note 一次验证完 demo
 * */
/*let result1 = validator.validate(form,rules,true);
if(!result1){
    console.log('出错的字段数组: ',validator.fields,'出错的字段对应的信息数组',validator.messages);
}*/

/**
 * @note 遇到第一次失败就停止验证  demo
 * */
/*let result2 = validator.validate(form,rules,false);
if(!result2){
    console.log('出错的字段: ',validator.field,'出错的字段对应的信息',validator.message);
}*/

/**
 * @note 单一字段验证  demo
 * */
/*let result3 = validator.validateField(form.hoppy,rules.hoppy,form,'hoppy');
if(!result3){
    console.log('出错的字段: ',validator.field,'出错的字段对应的信息',validator.message);
}*/